/// <reference path="./jquery-1.8.2.min.js" />
/// <reference path="./selfish.js" />
/// <reference path="./fourkill.util.js" />

var SpriteSheets = {};
SpriteSheets.Bird = SpriteSheet.newInstance("./sprites/web_bird_001.png", 3, 4);

var AdvancedSprites = {};
AdvancedSprites.Hero = AdvancedSprite.newInstance("./sprites/hero/", "hero", ".gif", {
    "walk": { "front": 6, "left": 8, "right": 8, "back": 6 },
    "run": { "front": 6, "left": 8, "right": 8, "back": 6 },
    "still": { "front": 1, "left": 1, "right": 1, "back": 1 }
}, false);
AdvancedSprites.Spencer = AdvancedSprite.newInstance("./sprites/spencer/", "spencer", ".png", {
    "walk": { "front": 3, "left": 3, "right": 3, "back": 3 },
    "still": { "front": 1, "left": 1, "right": 1, "back": 1 }
}, true);
AdvancedSprites.Hitler = AdvancedSprite.newInstance("./sprites/hitler/", "hitler", ".png", {
    "walk": { "front": 3, "left": 3, "right": 3, "back": 3 },
    "still": { "front": 1, "left": 1, "right": 1, "back": 1 },
    "aim": { "front": 1, "left": 1, "right": 1, "back": 1 }
}, true);
AdvancedSprites.Marine = AdvancedSprite.newInstance("./sprites/marine/", "marine", ".png", {
    "walk": { "front": 4, "left": 4, "right": 4, "back": 4, "frontright": 4, "frontleft": 4, "backright": 4, "backleft": 4 },
    "still": { "front": 1, "left": 1, "right": 1, "back": 1, "frontright": 1, "frontleft": 1, "backright": 1, "backleft": 1 }
}, false);

var SkyPainter = Base.extend({
    initialize: function initialize() {
        this.SECTION_COUNT = 6;
        this.MAGIC_NUMBER = 180.0;
    },
    paint: function paint(context) {
        var viewWidth = context.viewPort.size.w,
			skyHeight = Math.round(context.viewPort.size.h / 2.0),
			stripeWidth = Math.round(viewWidth / this.SECTION_COUNT);

        var transparentSkyBlue = "#8DD0EB",
			transparentLightBlue = "#A6D6E7";

        context.backLayer.fillStyle = transparentSkyBlue;
        context.backLayer.fillRect(0, 0, viewWidth, skyHeight);

        var rects = [], 
			b = false,
			width = 0;
        for (var x = 0; x < viewWidth; x++)
        {
            var num = x - Math.floor(context.camera.lineOfSight * this.MAGIC_NUMBER),
				l = num % stripeWidth;
            if (l < 0) l += stripeWidth; // Reverse.
            if (l < stripeWidth / 2)
            {
                b = true;
                width++;
            }
            else
            {
                if (b)
                {
                    rects.push(Rectangle.newInstance(x - width, 0, width, skyHeight));
                    b = false;
                    width = 0;
                }
            }
        }
        rects.push(Rectangle.newInstance(viewWidth - width, 0, width, skyHeight));

        context.backLayer.fillStyle = transparentLightBlue;
        var rect;
        for (var i=0; i < rects.length; i++)
        {
            rect = rects[i];
            context.backLayer.fillRect(rect.x, rect.y, rect.w, rect.h);
        }
    }
});

var Sky2Painter = Base.extend({
    initialize: function initialize() {
        this.SKY_BLUE = "#8DD0EB";
        this.SKY_LIGHT_BLUE = "#A6D6E7";
        this.SECTION_COUNT = 30.0; //out of 360 degrees of sky!
        this.SECTION_ANGLE = util._360 / this.SECTION_COUNT;
        this.SUN_LOCATION = util._180;
    },
    paint: function paint(context) {
        var viewWidth = context.viewPort.size.w,
            viewAngle = context.viewPort.horizontalViewableAngle,
			skyHeight = Math.round(context.viewPort.size.h / 2.0),
            totalSkyWidth = viewWidth * (util._360) / viewAngle,
            sectionWidth = totalSkyWidth / this.SECTION_COUNT,
            nibbleAngle = context.camera.lineOfSight,
            pixelOffset = 0,
            isAlternateColor = true;

        while (nibbleAngle < 0) nibbleAngle += util._360;
        isAlternateColor = Math.floor(nibbleAngle / this.SECTION_ANGLE) % 2;

        if (nibbleAngle >= this.SECTION_ANGLE) nibbleAngle = nibbleAngle % this.SECTION_ANGLE;
        offset = Math.round((nibbleAngle * sectionWidth) / this.SECTION_ANGLE);

        context.backLayer.fillStyle = isAlternateColor ? this.SKY_BLUE : this.SKY_LIGHT_BLUE;
        context.backLayer.fillRect(0, 0, viewWidth, skyHeight);

        context.backLayer.fillStyle = isAlternateColor ? this.SKY_LIGHT_BLUE : this.SKY_BLUE;
        for (var x = offset; x <= viewWidth; x += (sectionWidth * 2)) {
            var w = sectionWidth;
            if ((w + x) > viewWidth) w -= x - viewWidth;
            if (w > 0)
                context.backLayer.fillRect(x, 0, w, skyHeight);
        }

        // Sample sun thingy?
        var minView = (context.camera.lineOfSight - viewAngle / 2.0) - util.radians(5), // added degrees as a hack to make sure the entire sun shows up
            maxView = (context.camera.lineOfSight + viewAngle / 2.0) + util.radians(5);

        if (minView > util._360) while (minView > util._360) minView -= util._360;
        else while (minView < 0) minView += util._360;
        if (maxView > util._360) while (maxView > util._360) maxView -= util._360;
        else while (maxView < 0) maxView += util._360;
        if (minView < maxView) {
            if (this.SUN_LOCATION >= minView && this.SUN_LOCATION <= maxView) {
                var ssize = skyHeight / 8, halo = ssize*0.1;
                var soff = this.SUN_LOCATION - minView;
                var sloc = viewWidth - (soff * viewWidth / viewAngle);

                for (var i = 0; i < 4; i++) {
                    context.backLayer.fillStyle = "rgba(255, 255, 50, " + (0.1+(i*0.2)) + ")";
                    context.backLayer.beginPath();
                    context.backLayer.arc(sloc, skyHeight / 3, ssize - (i * halo), 0, util._360);
                    context.backLayer.closePath();
                    context.backLayer.fill();
                }
            }
        }
    }
});

var GroundPainter = Base.extend({
    initialize: function initialize() {
        this.SECTION_LENGTH = 20.0;
        this.GROUND_COLOR_1 = "#22AA22",
        this.GROUND_COLOR_2 = "#55AA55";
    },
    paint: function paint(context) {
        var totalMovement = Math.round(context.camera.totalMovement);
        if (totalMovement < 0) totalMovement += this.SECTION_LENGTH * 1000000;
        var offset = totalMovement % (this.SECTION_LENGTH);
        if (offset > 0) offset = (this.SECTION_LENGTH) - offset;
        if (offset < 0) offset = Math.abs(this.SECTION_LENGTH);

        var lineLocation = context.viewPort.size.h,
			centerLocation = lineLocation / 2,
			prevLineLocation = lineLocation,
			stripeSize = 1,
			stripeIndex = 0,
			current = 0,
			c = context.camera.h + context.camera.z,
			distance = 1.0 + offset,
			d2v = context.viewPort.distanceToView;

        context.backLayer.strokeStyle = this.GROUND_COLOR_1;
        context.backLayer.fillStyle = this.GROUND_COLOR_1;
        context.backLayer.fillRect(0, centerLocation, context.viewPort.size.w, context.viewPort.size.h - centerLocation);

        context.backLayer.strokeStyle = this.GROUND_COLOR_2;
        context.backLayer.fillStyle = this.GROUND_COLOR_2;
        while (lineLocation > centerLocation) {
            prevLineLocation = lineLocation;

            current = c / distance * d2v;
            lineLocation = centerLocation + Math.round(current * context.viewPort.scale);

            if (lineLocation < centerLocation) continue;
            else if (lineLocation >= context.viewPort.size.h)
                lineLocation = context.viewPort.size.h;
            else {
                stripeSize = prevLineLocation - lineLocation;
                if (stripeSize == 0) break;
                if (stripeIndex % 2 == 1) {
                    context.backLayer.fillRect(0, lineLocation, context.viewPort.size.w, stripeSize);
                }
            }
            distance += (this.SECTION_LENGTH / 2);
            stripeIndex++;
        }
    }
});

//*********************************** Object Painters ************************************
var FourTriangleTreePainter = Base.extend({
    initialize: function initialize() {
        this.TREE_TRIANGLES = 4;
        this.OPTIMAL_DISTANCE = 1500;
    },
    paint: function paint(context) {
        var location = context.gameObject.locationRelativeToCamera;
        if (location.visible) {
            var distance = location.distance;

            var rect = location.objectRectangle,
                x = rect.x,
                y = rect.y,
                width = rect.w,
                height = rect.h;

            if (distance < this.OPTIMAL_DISTANCE) {
                for (var i = 0; i < this.TREE_TRIANGLES; i++) {
                    var j = this.TREE_TRIANGLES - i - 1;
                    var l = x,
                        r = (x + width),
                        w = Math.abs(r - l),
                        w_off = w * (j * 0.10);
                    l += w_off;
                    r -= w_off;

                    context.frontLayer.fillStyle = context.gameObject.color;
                    context.frontLayer.beginPath();
                    context.frontLayer.moveTo(x + width / 2, y + (i * height / this.TREE_TRIANGLES) - height / 4);
                    context.frontLayer.lineTo(l, y + (i * height / this.TREE_TRIANGLES) + height / this.TREE_TRIANGLES);
                    context.frontLayer.lineTo(r, y + (i * height / this.TREE_TRIANGLES) + height / this.TREE_TRIANGLES);
                    context.frontLayer.closePath();
                    context.frontLayer.fill();

                    //context.frontLayer.fillStyle = context.gameObject.textColor;
                    //context.frontLayer.fillText("" + util.degrees(location.placement.angleFromCamera), x, y - 5);
                }
            } else {
                context.frontLayer.fillStyle = context.gameObject.color;
                context.frontLayer.beginPath();
                context.frontLayer.moveTo(x + width / 2, y);
                context.frontLayer.lineTo(x, y + height);
                context.frontLayer.lineTo(x + width, y + height);
                context.frontLayer.closePath();
                context.frontLayer.fill();
            }
        }
    }
});

var MistPainter = Base.extend({
    initialize: function initialize() { },
    paint: function paint(context) {
        var viewWidth = context.viewPort.size.w,
            viewHeight = context.viewPort.size.h,
            mistHeight = Math.round(context.viewPort.size.h * context.gameObject.percentage);

        var min = mistHeight / 5;
        if (min < 4) min = 4;
        context.frontLayer.fillStyle = context.gameObject.color;
        for (var i = min; i < mistHeight; i += (min / 2)) {
            context.frontLayer.fillRect(0, ((viewHeight - i) / 2), viewWidth, i);
        }
    }
});

var MapMarkerPainter = Base.extend({
    initialize: function initialize() { },
    paint: function paint(context) {
        var rect = context.gameObject.locationRelativeToCamera.objectRectangle,
            x = rect.x,
            y = rect.y,
            width = rect.w,
            height = rect.h;

        context.frontLayer.fillStyle = context.gameObject.textColor;
        context.frontLayer.fillText(context.gameObject.name, x, y - 5);
        context.frontLayer.fillStyle = context.gameObject.color;
        context.frontLayer.beginPath();
        context.frontLayer.moveTo(x, y);
        context.frontLayer.lineTo(x + width, y);
        context.frontLayer.lineTo(x + width / 2, y + height);
        context.frontLayer.closePath();
        context.frontLayer.fill();
    }
});

var CloudPainter = Base.extend({
    initialize: function initialize() { },
    paint: function paint(context) {
        var rect = context.gameObject.locationRelativeToCamera.objectRectangle,
            x = rect.x,
            y = rect.y,
            w = rect.w,
            h = rect.h,
            r = (h > 4.0 ? h / 4.0 : 1.0);

        context.frontLayer.fillStyle = context.gameObject.color;
        context.frontLayer.beginPath();
        context.frontLayer.moveTo(x + r, y);
        context.frontLayer.lineTo(x + w - r, y);
        context.frontLayer.quadraticCurveTo(x + w, y, x + w, y + r);
        context.frontLayer.lineTo(x + w, y + h - r);
        context.frontLayer.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
        context.frontLayer.lineTo(x + r, y + h);
        context.frontLayer.quadraticCurveTo(x, y + h, x, y + h - r);
        context.frontLayer.lineTo(x, y + r);
        context.frontLayer.quadraticCurveTo(x, y, x + r, y);
        context.frontLayer.closePath();
        context.frontLayer.fill();
    }
});

var SpriteSheetPainter = Base.extend({
    initialize: function initialize() {
        this.SHADOW_COLOR = "rgba(0, 0, 0, 0.3)";
        this.spriteSheet = SpriteSheets.Bird;
    },
    paint: function paint(context) {
        var location = context.gameObject.locationRelativeToCamera,
            rect = location.objectRectangle,
            shRect = location.shadowRectangle,
            vp = context.viewPort,
            go = context.gameObject;
        
        if (location.visible)
        {
            if (!(shRect.x > vp.size.w || shRect.y > vp.size.h ||
                shRect.getRight() < 0 || shRect.getBottom() < 0))
            {
                context.backLayer.fillStyle = this.SHADOW_COLOR;
                util.fillEllipse(context.backLayer, shRect.x, shRect.y, shRect.w, shRect.h);
            }

            if (rect.x > vp.size.w || rect.y > vp.size.h ||
                rect.getRight() < 0 || rect.getBottom() < 0 ||
                rect.w <= 0 || rect.h <= 0) return;

            //context.frontLayer.fillStyle = context.gameObject.color;
            //context.frontLayer.fillRect(rect.x, rect.y, rect.w, rect.h);

            //this.spriteSheet
            //var spriteState = go.z > 0 ? "fly" : "walk"; // need to look at this!
            var spriteStates = [];
            spriteStates.push((go.speed > 0) ? "moving" : "still");
            spriteStates.push((go.z > 0) ? "fly" : "walk");
            //else spriteState = 0;

            //TODO: need a sprite state! (Above)
            var ss = this.spriteSheet;
            if (ss.isReady()) {
                var fIdx = go.frameIndex, fCount = ss.getFrameCount(spriteStates);
                if (fCount > 1) {
                    if (fIdx >= (fCount - 1))
                        go.frameIncrement = -1;
                    else if (fIdx <= 0)
                        go.frameIncrement = 1;
                    fIdx += go.frameIncrement;
                }
                else fIdx = 0;
                go.frameIndex = fIdx;

                var direction = null;
                if (ss.directions == 8) {
                    direction = util.determine8WayDirection(location.placement.bearing);
                }
                else {
                    direction = util.determine4WayDirection(location.placement.bearing);
                }
                /*pctx.frontLayer.fillStyle = "#F00";
                pctx.frontLayer.fillText(direction.toUpperCase() + " " + util.degrees(location.placement.bearing), rect.x, rect.y);*/

                context.frontLayer.drawImage(ss.image,
                    ss.getXOff(go.frameIndex), ss.getYOff(direction), ss.w, ss.h,
                    rect.x, rect.y, rect.w, rect.h);
            }
        }
    }
});


var AdvancedSpritePainter = Base.extend({
    initialize: function initialize() {
        this.SHADOW_COLOR = "rgba(0, 0, 0, 0.3)";
    },
    paint: function paint(context) {
        var location = context.gameObject.locationRelativeToCamera,
            rect = location.objectRectangle,
            shRect = location.shadowRectangle,
            vp = context.viewPort,
            go = context.gameObject;

        if (location.visible) {

            if (rect.x > vp.size.w || rect.y > vp.size.h ||
                rect.getRight() < 0 || rect.getBottom() < 0 ||
                rect.w <= 0 || rect.h <= 0) return;

            //if (go.sprite == null)
            //go.sprite = AdvancedSprites.Spencer;
            var ss = go.sprite;

            if (ss == null) {
                var i = 23;
                i++;
            }
            else {
                var spriteState = "";
                if (go.speed <= 0) spriteState = "still";
                else if (go.speed >= 2 && ss.supportsState("run")) spriteState = "run";
                else spriteState = "walk";

                var direction = null;
                if (ss.directions == 8) {
                    direction = util.determine8WayDirection(location.placement.bearing);
                }
                else {
                    direction = util.determine4WayDirection(location.placement.bearing);
                }

                //TODO: need a sprite state! (Above)
                if (ss != null && ss.isReady()) {
                    go.frameIncrement = 1;
                    var fIdx = go.frameIndex, fCount = ss.getFrameCount(spriteState, direction);

                    if (fCount > 1) {
                        if (go.bounce) {
                            // Bounce Logic:
                            if (fIdx >= (fCount - 1))
                                go.frameIncrement = -1;
                            else if (fIdx <= 0)
                                go.frameIncrement = 1;
                            fIdx += go.frameIncrement;
                        }
                        else {
                            // Rotate Logic:
                            if (fIdx >= (fCount - 1))
                                fIdx = 0;
                            else
                                fIdx += go.frameIncrement;
                        }
                    }
                    else fIdx = 0;
                    go.frameIndex = fIdx;


                    var image = ss.getImage(spriteState, direction, fIdx);
                    var x = rect.x, y = rect.y, w = rect.w, h = rect.h, ih = ss.getHeight(spriteState, direction, fIdx), iw = ss.getWidth(spriteState, direction, fIdx);
                    w = (h * iw) / ih; // make the width 

                    if (!(shRect.x > vp.size.w || shRect.y > vp.size.h ||
                        shRect.getRight() < 0 || shRect.getBottom() < 0)) {
                        context.backLayer.fillStyle = this.SHADOW_COLOR;
                        util.fillEllipse(context.backLayer, shRect.x, shRect.y, w, shRect.h);
                    }

                    /*pctx.frontLayer.fillStyle = "#F00";
                    pctx.frontLayer.fillText(direction.toUpperCase() + " " + util.degrees(location.placement.bearing), rect.x, rect.y);*/


                    context.frontLayer.drawImage(image, x, y, w, h);
                }
            }
        }
    }
});

var Painters = {};
Painters.Sky = SkyPainter.newInstance();
Painters.Sky2 = Sky2Painter.newInstance();
Painters.Ground = GroundPainter.newInstance();
Painters.Mist = MistPainter.newInstance();
Painters.FourTriangleTree = FourTriangleTreePainter.newInstance();
Painters.MapMarker = MapMarkerPainter.newInstance();
Painters.Cloud = CloudPainter.newInstance();
Painters.SpriteSheetPainter = SpriteSheetPainter.newInstance();
Painters.AdvancedSpritePainter = AdvancedSpritePainter.newInstance();
